package Util;

import java.io.*;

/**
 * @author 黄衡熙
 * @version 1.0
 */
public class FileUtil {
    /**
     * 将一个文件拷贝一份到指定的文件中
     * @param src    源文件
     * @param target 目标文件
     */
    public static void copyFile(File src, File target) {
        try (
                InputStream in = new FileInputStream(src);
                OutputStream out = new FileOutputStream(target);
        ) {
            // 先读取源文件中的内容
            byte[] b = new byte[1024];
            int i = -1;
            while ((i = in.read(b)) != -1) {
                // 将读取到的内容写入到目标文件中
                out.write(b, 0, i);
            }
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 将一个文件拷贝一份到指定的文件中
     * @param src    源文件
     * @param target 目标文件
     */
    public static void copyFile(String src, String target) {
        copyFile(new File(src), new File(target));
    }

    /**
     * 将一个目录中所有的文件拷贝到指定目录中
     * @param src    源目录
     * @param target 目标目录
     */
    public static void copyDirectory(String src, String target) {
        File srcFile = new File(src);
        // 获取该目录中所有资源
        File[] files = srcFile.listFiles();

        // 创建目标目录
        File targetFile = new File(target);
        targetFile.mkdirs();

        // 遍历源目录中所有资源
        for (File file : files) {
            // 如果当前资源是一个文件
            if (file.isFile()) {
                // 则将该文件拷贝到目标目录中
                // 此时该文件的路径为:目标目录名+路径分隔符+当前文件名
                copyFile(file, new File(target + File.separator + file.getName()));
            }
        }
    }

    /**
     * 将一个目录中的文件与子目录递归拷贝到一个指定的目录中
     * @param src    源目录
     * @param target 目标目录
     */
    public static void recursiveCopy(String src, String target) {
        File srcFile = new File(src);
        File[] files = srcFile.listFiles();

        File targetFile = new File(target);
        targetFile.mkdirs();

        // 遍历源目录中所有资源
        for (File file : files) {
            // 如果当前资源是一个文件,则直接拷贝
            if (file.isFile()) {
                // 则将该文件拷贝到目标目录中
                // 此时该文件的路径为:目标目录名+路径分隔符+当前文件名
                copyFile(file, new File(target + File.separator + file.getName()));
            } else {
                // 如果是目录,则递归调用
                recursiveCopy(file.getAbsolutePath(), target + File.separator + file.getName());
            }
        }

    }

    /**
     * 拆分文件,将一个文件按照指定大小拆分成多个文件,每一个文件名字为:原名字_index,index从1开始,每次自增1
     * 提示:一个输入流,多个输出流,在输出时,每循环一次,输出一个子文件
     * @param path
     * @param length
     */
    public static void splitFile(String path, int length) throws IOException {
        FileOutputStream out = null;
        try (
                FileInputStream in = new FileInputStream(path);
        ) {
            // 拆分的文件,每一个文件的大小为length
            // 因此,每次读取length个字节
            byte[] b = new byte[length];
            int i = -1;
            int index = 1;
            while ((i = in.read(b)) != -1) {
                // 每循环一次,生成一个输出流
                out = new FileOutputStream(path + "_" + index);
                out.write(b, 0, i);
                out.flush();
                out.close();
                System.out.println("提示:文件" + path + "_" + index + "已经拆分成功");
                index++;
            }
            System.out.println("提示:文件全部拆分成功");
        } catch (FileNotFoundException e) {
            throw e;
        } catch (IOException e) {
            throw e;
        }
    }

    /**
     * 合并文件,将之前拆分的文件合并为一个文件,将子文件的_index部分删除作为文件名
     * 提示:一个输出流,多个输入流
     * 传入的是第一个文件,会按照传入的文件的格式自动搜索所有同格式的文件,将这些文件进行合并
     * 文件格式:文件名_索引号
     * @param firstFile
     */
    public static void mergeFile(File firstFile) throws IOException {
        // 获取文件名
        String path = firstFile.getAbsolutePath();
        // 截取字符串,从起始位置截取到最后一次出现_的位置
        path = path.substring(0, path.lastIndexOf("_"));
        try (FileOutputStream out = new FileOutputStream(path)) {
            // 定义合并前文件的后缀值
            int index = 1;
            File file = null;
            // 每次进入循环,合并一个文件
            while ((file = new File(path + "_" + index++)).exists()) {
                // 定义多个输入流
                FileInputStream in = new FileInputStream(file);
                // 拷贝
                byte[] b = new byte[1024 * 1024];
                int i = -1;
                while ((i = in.read(b)) != -1) {
                    out.write(b, 0, i);
                    out.flush();
                }
                in.close();
            }
            System.out.println("提示:文件" + path + "合并完成");
        } catch (FileNotFoundException e) {
            throw e;
        } catch (IOException e) {
            throw e;
        }
    }
    /**
     * 文件加密
     * 读取文件中的每一个字节,根据指定的密码对其进行加密,加密后的文件添加.sec后缀
     * 例如:a.txt --> a.txt.sec
     * 提示:将文件中读取的每一个字节都通过指定密码执行异或操作
     * @param file
     * @param password
     */
    public static void encoded(File file, int password) throws IOException {
        try (
                FileInputStream in = new FileInputStream(file);
                FileOutputStream out = new FileOutputStream(file.getAbsolutePath() + ".sec");
        ) {
            int i = -1;
            while ((i = in.read()) != -1) {
                out.write(i ^ password);
            }
        } catch (FileNotFoundException e) {
            throw e;
        } catch (IOException e) {
            throw e;
        }
    }

    /**
     * 文件解密
     * 读取加密后的文件中的每一个字节,根据指定的密码对其进行解密,解密后的文件去除.sec后缀
     * 例如:a.txt.sec --> a.txt
     * 提示:将文件中读取的每一个字节都通过指定密码再次执行异或操作
     * @param file
     * @param password
     */
    public static void decoded(File file, int password) throws IOException {
        try (
                FileInputStream in = new FileInputStream(file);
                FileOutputStream out = new FileOutputStream(file.getAbsolutePath().substring(0, file.getAbsolutePath().lastIndexOf(".")));
        ) {
            int i = -1;
            while ((i = in.read()) != -1) {
                out.write(i ^ password);
            }
        } catch (FileNotFoundException e) {
            throw e;
        } catch (IOException e) {
            throw e;
        }
    }

    public static void main(String[] args) throws IOException {
        //encoded(new File("hello.txt"),123);
        decoded(new File("hello.txt.sec"), 123);
    }
}
